home *** CD-ROM | disk | FTP | other *** search
/ ShareWare OnLine 2 / ShareWare OnLine Volume 2 (CMS Software)(1993).iso / os2 / remin301.zip / REMIN300.ZIP / FILES.C < prev    next >
C/C++ Source or Header  |  1992-11-10  |  15KB  |  531 lines

  1. /***************************************************************/
  2. /*                                                             */
  3. /*  FILES.C                                                    */
  4. /*                                                             */
  5. /*  Controls the opening and closing of files, etc.  Also      */
  6. /*  handles caching of lines and reading of lines from         */
  7. /*  files.                                                     */
  8. /*                                                             */
  9. /*  This file is part of REMIND.                               */
  10. /*  Copyright (C) 1992 by David F. Skoll.                      */
  11. /*                                                             */
  12. /***************************************************************/
  13.  
  14. #include "config.h"
  15. #include <stdio.h>
  16. #ifdef HAVE_STDLIB_H
  17. #include <stdlib.h>
  18. #endif
  19. #ifdef HAVE_MALLOC_H
  20. #include <malloc.h>
  21. #endif
  22. #include <string.h>
  23. #include <ctype.h>
  24. #include <sys/types.h>
  25. #include <sys/stat.h>
  26. #include <time.h>
  27.  
  28. #ifdef __MSDOS__
  29. #include <io.h>
  30. #endif
  31.  
  32. #ifdef __MSC__
  33. #include <dos.h>
  34. #endif
  35.  
  36. #include "config.h"
  37. #include "types.h"
  38. #include "protos.h"
  39. #include "globals.h"
  40. #include "err.h"
  41.  
  42. /* Define the structures needed by the file caching system */
  43. typedef struct _cache_ {
  44.    struct _cache_ *next;
  45.    char *text;
  46.    int LineNo;
  47. } CachedLine;
  48.  
  49. typedef struct _cheader_ {
  50.    struct _cheader_ *next;
  51.    char *filename;
  52.    CachedLine *cache;
  53. } CachedFile;
  54.  
  55. /* Define the structures needed by the INCLUDE file system */
  56. typedef struct {
  57.    char *filename;
  58.    int LineNo;
  59.    unsigned int IfFlags;
  60.    int NumIfs;
  61.    long offset;
  62.    CachedLine *CLine;
  63. } IncludeStruct;
  64.  
  65. static CachedFile *CachedFiles = (CachedFile *) NULL;
  66. static CachedLine *CLine = (CachedLine *) NULL;
  67.  
  68. static FILE *fp;
  69.  
  70. static IncludeStruct IStack[INCLUDE_NEST];
  71. static int IStackPtr = 0;
  72.  
  73. PRIVATE int ReadLineFromFile ARGS ((void));
  74. PRIVATE int CacheFile ARGS ((const char *fname));
  75. PRIVATE void DestroyCache ARGS ((CachedFile *cf));
  76.  
  77. /***************************************************************/
  78. /*                                                             */
  79. /*  ReadLine                                                   */
  80. /*                                                             */
  81. /*  Read a line from the file or cache.                        */
  82. /*                                                             */
  83. /***************************************************************/
  84. #ifdef HAVE_PROTOS
  85. PUBLIC int ReadLine(void)
  86. #else
  87. int ReadLine()
  88. #endif
  89. {
  90.    int r;
  91.  
  92. /* If we're at the end of a file, pop */
  93.    while (!CLine && !fp) {
  94.       r = PopFile();
  95.       if (r) return r;
  96.    }
  97.  
  98. /* If it's cached, read line from the cache */
  99.    if (CLine) {
  100.       CurLine = CLine->text;
  101.       LineNo = CLine->LineNo;
  102.       CLine = CLine->next;
  103.       FreshLine = 1;
  104.       if (DebugFlag & DB_ECHO_LINE) OutputLine(ErrFp);
  105.       return OK;
  106.    }
  107.  
  108. /* Not cached.  Read from the file. */
  109.    CurLine = LineBuffer;
  110.    return ReadLineFromFile();
  111. }
  112.  
  113. /***************************************************************/
  114. /*                                                             */
  115. /*  ReadLineFromFile                                           */
  116. /*                                                             */
  117. /*  Read a line from the file pointed to by fp.                */
  118. /*                                                             */
  119. /***************************************************************/
  120. #ifdef HAVE_PROTOS
  121. PRIVATE int ReadLineFromFile(void)
  122. #else
  123. static ReadLineFromFile()
  124. #endif
  125. {
  126.    int l;
  127.    char *ptr;
  128.  
  129.    *LineBuffer = (char) 0;
  130.    l = 0;
  131.    ptr = LineBuffer;
  132.    while(fp) {
  133.       (void) fgets(ptr, LINELEN-l, fp);
  134.       LineNo++;
  135.       if (ferror(fp)) return E_IO_ERR;
  136.       if (feof(fp)) {
  137.          fclose(fp);
  138.      fp = NULL;
  139.       }
  140.       l = strlen(LineBuffer);
  141.       if (l && (LineBuffer[l-1] == '\n')) LineBuffer[--l] = '\0';
  142.       if (l && (LineBuffer[l-1] == '\\')) {
  143.      l--;
  144.      ptr = LineBuffer+l;
  145.      if (l >= LINELEN-1) return E_LINE_2_LONG;
  146.      continue;
  147.       }
  148.       FreshLine = 1;
  149.       if (DebugFlag & DB_ECHO_LINE) OutputLine(ErrFp);
  150.       return OK;
  151.    }
  152.    return OK;
  153. }
  154.  
  155. /***************************************************************/
  156. /*                                                             */
  157. /*  OpenFile                                                   */
  158. /*                                                             */
  159. /*  Open a file for reading.  If it's in the cache, set        */
  160. /*  CLine.  Otherwise, open it on disk and set fp.  If         */
  161. /*  ShouldCache is 1, cache the file                           */
  162. /*                                                             */
  163. /***************************************************************/
  164. #ifdef HAVE_PROTOS
  165. PUBLIC int OpenFile(const char *fname)
  166. #else
  167. int OpenFile(fname)
  168. char *fname;
  169. #endif
  170. {
  171.    CachedFile *h = CachedFiles;
  172.    int r;
  173.  
  174. /* If it's in the cache, get it from there. */
  175.  
  176.    while (h) {
  177.       if (!strcmp(fname, h->filename)) {
  178.      CLine = h->cache;
  179.      STRSET(FileName, fname);
  180.      LineNo = 0;
  181.      if (FileName) return OK; else return E_NO_MEM;
  182.       }
  183.       h = h->next;
  184.    }
  185.    fp = fopen(fname, "r");
  186.    if (!fp) return E_CANT_OPEN;
  187.    CLine = NULL;
  188.    if (ShouldCache) {
  189.       LineNo = 0;
  190.       r = CacheFile(fname);
  191.       if (r == OK) {
  192.          fp = NULL;
  193.      CLine = CachedFiles->cache;
  194.       } else {
  195.          fp = fopen(fname, "r");
  196.      if (!fp) return E_CANT_OPEN;
  197.       }
  198.    }
  199.    STRSET(FileName, fname);
  200.    LineNo = 0;
  201.    if (FileName) return OK; else return E_NO_MEM;
  202. }
  203.  
  204. /***************************************************************/
  205. /*                                                             */
  206. /*  CacheFile                                                  */
  207. /*                                                             */
  208. /*  Cache a file in memory.  If we fail, set ShouldCache to 0  */
  209. /*  Returns an indication of success or failure.               */
  210. /*                                                             */
  211. /***************************************************************/
  212. #ifdef HAVE_PROTOS
  213. PRIVATE int CacheFile(const char *fname)
  214. #else
  215. static int CacheFile(fname)
  216. char *fname;
  217. #endif
  218. {
  219.    int r;
  220.    CachedFile *cf;
  221.    CachedLine *cl;
  222.    char *s;
  223.  
  224.    cl = NULL;
  225. /* Create a file header */
  226.    cf = NEW(CachedFile);
  227.    cf->cache = NULL;
  228.    if (!cf) { ShouldCache = 0; fclose(fp); return E_NO_MEM; }
  229.    cf->filename = StrDup(fname);
  230.    if (!cf->filename) {
  231.       ShouldCache = 0;
  232.       fclose(fp);
  233.       free(cf);
  234.       return E_NO_MEM;
  235.    }
  236.  
  237. /* Read the file */
  238.    while(fp) {
  239.       r = ReadLineFromFile();
  240.       if (r) {
  241.          DestroyCache(cf);
  242.      ShouldCache = 0;
  243.      if(fp) fclose(fp);
  244.      return r;
  245.       }
  246. /* Skip blank chars */
  247.       s = LineBuffer;
  248.       while (isspace(*s)) s++;
  249.       if (*s && *s!=';' && *s!='#') {
  250. /* Add the line to the cache */
  251.          if (!cl) {
  252.         cf->cache = NEW(CachedLine);
  253.         if (!cf->cache) {
  254.            DestroyCache(cf);
  255.            ShouldCache = 0;
  256.            if(fp) fclose(fp);
  257.            return E_NO_MEM;
  258.             }
  259.         cl = cf->cache;
  260.          } else {
  261.         cl->next = NEW(CachedLine);
  262.         if (!cl->next) {
  263.            DestroyCache(cf);
  264.            ShouldCache = 0;
  265.            if(fp) fclose(fp);
  266.            return E_NO_MEM;
  267.             }
  268.         cl = cl->next;
  269.          }
  270.      cl->next = NULL;
  271.      cl->LineNo = LineNo;
  272.      cl->text = StrDup(s);
  273.      if (!cl->text) {
  274.         DestroyCache(cf);
  275.         ShouldCache = 0;
  276.         if(fp) fclose(fp);
  277.         return E_NO_MEM;
  278.          }
  279.       }
  280.    }
  281.  
  282. /* Put the cached file at the head of the queue */
  283.    cf->next = CachedFiles;
  284.    CachedFiles = cf;
  285.  
  286.    return OK;
  287. }
  288.  
  289. /***************************************************************/
  290. /*                                                             */
  291. /*  PopFile - we've reached the end.  Pop up to the previous   */
  292. /*  file, or return E_EOF                                      */
  293. /*                                                             */
  294. /***************************************************************/
  295. #ifdef HAVE_PROTOS
  296. PUBLIC int PopFile(void)
  297. #else
  298. int PopFile()
  299. #endif
  300. {
  301.    IncludeStruct *i;
  302.  
  303.    if (!Hush && NumIfs) Eprint("Warning: Missing ENDIF");
  304.    if (!IStackPtr) return E_EOF;
  305.    IStackPtr--;
  306.    i = &IStack[IStackPtr];
  307.  
  308.    LineNo = i->LineNo;
  309.    IfFlags = i->IfFlags;
  310.    NumIfs = i->NumIfs;
  311.    CLine = i->CLine;
  312.    fp = NULL;
  313.    STRSET(FileName, i->filename);
  314.    if (!CLine && (i->offset != -1L)) {
  315.    /* We must open the file, then seek to specified position */
  316.       fp = fopen(i->filename, "r");
  317.       if (!fp) return E_CANT_OPEN;
  318.       (void) fseek(fp, i->offset, 0);  /* Trust that it works... */
  319.    }
  320.    free(i->filename);
  321.    return OK;
  322. }
  323.  
  324. /***************************************************************/
  325. /*                                                             */
  326. /*  DoInclude                                                  */
  327. /*                                                             */
  328. /*  The INCLUDE command.                                       */
  329. /*                                                             */
  330. /***************************************************************/
  331. #ifdef HAVE_PROTOS
  332. PUBLIC int DoInclude(ParsePtr p)
  333. #else
  334. int DoInclude(p)
  335. ParsePtr p;
  336. #endif
  337. {     
  338.     char tok[TOKSIZE];
  339.     int r, e;
  340.  
  341.     if(r=ParseToken(p, tok)) return r;
  342.     e = VerifyEoln(p); 
  343.     if (e) Eprint("%s", ErrMsg[e]);
  344.     if(r=IncludeFile(tok)) return r;
  345.     NumIfs = 0;
  346.     IfFlags = 0;
  347.     return OK;
  348. }
  349.  
  350. /***************************************************************/
  351. /*                                                             */
  352. /*  IncludeFile                                                */
  353. /*                                                             */
  354. /*  Process the INCLUDE command - actually do the file         */
  355. /*  inclusion.                                                 */
  356. /*                                                             */
  357. /***************************************************************/
  358. #ifdef HAVE_PROTOS
  359. PUBLIC int IncludeFile(const char *fname)
  360. #else
  361. int IncludeFile(fname)
  362. char *fname;
  363. #endif
  364. {
  365.    IncludeStruct *i;
  366.    int r;
  367.  
  368.    if (IStackPtr+1 >= INCLUDE_NEST) return E_NESTED_INCLUDE;
  369.    i = &IStack[IStackPtr];
  370.  
  371.    i->filename = StrDup(FileName);
  372.    if (!i->filename) return E_NO_MEM;
  373.    i->LineNo = LineNo;
  374.    i->NumIfs = NumIfs;
  375.    i->IfFlags = IfFlags;
  376.    i->CLine = CLine;
  377.    i->offset = -1L;
  378.    if (fp) {
  379.       i->offset = ftell(fp);
  380.       fclose(fp);
  381.       fp = (FILE *) NULL;
  382.    }
  383.  
  384.    IStackPtr++;
  385.  
  386.    /* Try to open the new file */
  387.    if (!OpenFile(fname)) {
  388.       return OK;
  389.    }
  390.    /* Ugh!  We failed!  */
  391.    if (r=PopFile()) return r;
  392.    return E_CANT_OPEN;
  393. }
  394.  
  395. /***************************************************************/
  396. /*                                                             */
  397. /* GetAccessDate - get the access date of a file.              */
  398. /*                                                             */
  399. /***************************************************************/
  400. #ifdef HAVE_PROTOS
  401. PUBLIC int GetAccessDate(char *file)
  402. #else
  403. int GetAccessDate(file)
  404. char *file;
  405. #endif
  406. {
  407.    struct stat statbuf;
  408.    struct tm *t1;
  409.  
  410.    if (stat(file, &statbuf)) return -1;
  411. #ifdef __TURBOC__
  412.    t1 = localtime( (time_t *) &(statbuf.st_atime) );
  413. #else
  414.    t1 = localtime(&(statbuf.st_atime));
  415. #endif
  416.  
  417.    if (t1->tm_year + 1900 < BASE)
  418.       return 0;
  419.    else
  420.       return Julian(t1->tm_year+1900, t1->tm_mon, t1->tm_mday);
  421. }
  422.  
  423. /***************************************************************/
  424. /*                                                             */
  425. /*  SetAccessDate                                              */
  426. /*                                                             */
  427. /*  Used only by DOS to set access date after we close the     */
  428. /*  file.  Not needed for UNIX.                                */
  429. /*                                                             */
  430. /***************************************************************/
  431. #ifdef __MSDOS__
  432. /*
  433.  * WARNING WARNING WARNING WARNING
  434.  * In the version of Turbo C which I have, there is a bug in the
  435.  * stdio.h file.  The following lines correct the bug.  YOU MAY
  436.  * HAVE TO REMOVE THESE LINES FOR LATER VERSIONS OF TURBOC
  437.  */
  438. #ifdef __TURBOC__
  439. #ifndef fileno
  440. #define fileno(f) ((f)->fd)
  441. #endif
  442. #endif
  443.  
  444. #ifdef HAVE_PROTOS
  445. PUBLIC int SetAccessDate(char *fname, int jul)
  446. #else
  447. int SetAccessDate(fname, jul)
  448. char *fname;
  449. int jul;
  450. #endif
  451. {
  452.    int y, m, d;
  453. #ifdef __TURBOC__   
  454.    struct ftime ft;
  455. #endif   
  456.    FILE *f;
  457.  
  458.    FromJulian(jul, &y, &m, &d);
  459.    
  460. #ifdef __TURBOC__   
  461.    ft.ft_tsec = 0;
  462.    ft.ft_min = 0;
  463.    ft.ft_hour = 12;  /* Arbitrarily set time to noon. */
  464.    ft.ft_day = (unsigned int) d;
  465.    ft.ft_month = (unsigned int) m+1;
  466.    ft.ft_year = (unsigned int) (y - 1980);
  467. #endif
  468.  
  469.    f = fopen(fname, "r");
  470.  
  471. #ifdef __TURBOC__   
  472.    if (!f || setftime(fileno(f) , &ft)) {
  473. #endif
  474.  
  475. #ifdef __MSC__
  476.    if (!f || _dos_setftime(fileno(f),
  477.     ((y-1980)<<9) + (m+1)<<5 + d,
  478.     (12<<11))) {
  479. #endif       
  480.       fprintf(ErrFp, "Can't reset access date of %s\n", fname);
  481.       if (f) fclose(f);
  482.       return -1;
  483.    }
  484.  
  485.    fclose(f);
  486.    return 0;
  487. }
  488. #endif /* __MSDOS__ */
  489.  
  490. /***************************************************************/
  491. /*                                                             */
  492. /*  DestroyCache                                               */
  493. /*                                                             */
  494. /*  Free all the memory used by a cached file.                 */
  495. /*                                                             */
  496. /***************************************************************/
  497. #ifdef HAVE_PROTOS
  498. PRIVATE void DestroyCache(CachedFile *cf)
  499. #else
  500. static void DestroyCache(cf)
  501. CachedFile *cf;
  502. #endif
  503. {
  504.    CachedLine *cl, *cnext;
  505.    if (cf->filename) free(cf->filename);
  506.    cl = cf->cache;
  507.    while (cl) {
  508.       if (cl->text) free (cl->text);
  509.       cnext = cl->next;
  510.       free(cl);
  511.       cl = cnext;
  512.    }
  513.    free(cf);
  514. }
  515.  
  516. /***************************************************************/
  517. /*                                                             */
  518. /*  TopLevel                                                   */
  519. /*                                                             */
  520. /*  Returns 1 if current file is top level, 0 otherwise.       */
  521. /*                                                             */
  522. /***************************************************************/
  523. #ifdef HAVE_PROTOS
  524. PUBLIC int TopLevel(void)
  525. #else
  526. int TopLevel()
  527. #endif
  528. {
  529.    return !IStackPtr;
  530. }
  531.